package org.anddev.andengine.engine.camera.hud.controls;

import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.camera.hud.controls.AnalogOnScreenControl;
import org.anddev.andengine.opengl.texture.region.TextureRegion;

import android.util.FloatMath;

/**
 * 
 * @author adam
 *
 * Analog controls restricted to a circular radius instead of square
 * Taken from forum post by AngrySpade here:
 * http://www.andengine.org/forums/post5720.html
 *
 */

public class RadiusBoundAnalogOnScreenControl extends AnalogOnScreenControl {
	 
    private float maxDistance = 0.5f;
    private float minDistance = 0.3f;
 
    public RadiusBoundAnalogOnScreenControl(int pX, int pY, Camera pCamera, TextureRegion pControlBaseTextureRegion, TextureRegion pControlKnobTextureRegion, float pTimeBetweenUpdates, IAnalogOnScreenControlListener pAnalogOnScreenControlListener) {
        super(pX, pY, pCamera, pControlBaseTextureRegion, pControlKnobTextureRegion, pTimeBetweenUpdates, pAnalogOnScreenControlListener);
    }
 
    public RadiusBoundAnalogOnScreenControl(int pX, int pY, Camera pCamera, TextureRegion pControlBaseTextureRegion, TextureRegion pControlKnobTextureRegion, float pTimeBetweenUpdates, long pOnControlClickMaximumMilliseconds, IAnalogOnScreenControlListener pAnalogOnScreenControlListener) {
        super(pX, pY, pCamera, pControlBaseTextureRegion, pControlKnobTextureRegion, pTimeBetweenUpdates, pOnControlClickMaximumMilliseconds, pAnalogOnScreenControlListener);
    }
 
    @Override
    protected void onUpdateControlKnob(float pRelativeX, float pRelativeY) {    
        float x = pRelativeX;
        float y = pRelativeY;
       
        if ((pRelativeX != 0) && (pRelativeY != 0)) {
            float hypotenuse = FloatMath.sqrt((pRelativeX * pRelativeX) + (pRelativeY * pRelativeY));
       
            if (hypotenuse > this.maxDistance) {
                float absoluteX = Math.abs(pRelativeX);
                float absoluteY = Math.abs(pRelativeY);
                float rad = (float) Math.atan(absoluteY / absoluteX);
 
                x = (float) (Math.cos(rad) * this.maxDistance) * ((pRelativeX < 0) ? -1 : 1);
                y = (float) (Math.sin(rad) * this.maxDistance) * ((pRelativeY < 0) ? -1 : 1);
            }
            else if (hypotenuse < this.minDistance) {
                float absoluteX = Math.abs(pRelativeX);
                float absoluteY = Math.abs(pRelativeY);
                float rad = (float) Math.atan(absoluteY / absoluteX);
               
                x = (float) (Math.cos(rad) * this.minDistance) * ((pRelativeX < 0) ? -1 : 1);
                y = (float) (Math.sin(rad) * this.minDistance) * ((pRelativeY < 0) ? -1 : 1);
            }
        }    
       
        super.onUpdateControlKnob(x, y);
    }
 
    public float getMaxDistance() {
        return maxDistance;
    }
 
    public void setMaxDistance(float maxDistance) {
        this.maxDistance = maxDistance;
    }
 
}